#!/usr/bin/env pythonw

import sys, profile

import config.config as config

from controller.note_controller import *

from view.helper import *
from view.search_frame import *
from view.list_frame import *
from view.display_frame import *
from view.background_frame import *
from view.edit_frame import *
from view.pretty_display_frame import *

from view.pretty_display_frame import *
from datetime import date as date
import yaml

import time

class Meno(wx.App):
  def OnInit(self):
    screen_x = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X)
    screen_y = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y)

    golden_ratio = 1.618  
    space = 30
    
    self.search_frames_snapshot = []
    self.edit_frames_snapshot = []
    self.current_mode = 'search'
    
    self.note = NoteController(config.db)
    
    #-------------------------------------------------------------------------
    # Search Frames
    #-------------------------------------------------------------------------
        
    search_frame_width = ( 1 / golden_ratio - ( 1 - 1 / golden_ratio ) ) * screen_x - 4 * space
    search_frame_height = 80

    search_frame_pos_x = (screen_x - search_frame_width ) / 2
    search_frame_pos_y = screen_y / golden_ratio - search_frame_height / 2
    

    list_frame_width = screen_x - ( screen_x - space * 2 )/ golden_ratio - space
    list_frame_height = screen_y - space * 2
    list_frame_pos_x = space
    list_frame_pos_y = (screen_y  - list_frame_height ) / 2
    
    display_frame_width = list_frame_width
    display_frame_height = list_frame_height
    display_frame_pos_x = screen_x - list_frame_pos_x - list_frame_width
    display_frame_pos_y = list_frame_pos_y
    

    
    self.search_frame = SearchFrame(None, 'Search', (search_frame_pos_x, search_frame_pos_y), (search_frame_width, search_frame_height))
    self.list_frame = ListFrame(None, 'List', (list_frame_pos_x, list_frame_pos_y), (list_frame_width, list_frame_height))
    self.plain_display_frame = DisplayFrame(None, 'Preview', (display_frame_pos_x, display_frame_pos_y), (display_frame_width, display_frame_height))
    self.pretty_display_frame = PrettyDisplayFrame(None, 'PrettyPreview', (display_frame_pos_x, display_frame_pos_y), \
      (display_frame_width, display_frame_height))
    self.background_frame = BackgroundFrame(None, 'Background', (0, 0), (screen_x, screen_y))
    self.SetTopWindow(self.search_frame)


    self.display_frame = self.plain_display_frame

    self.search_frames = [self.search_frame, self.list_frame, self.pretty_display_frame, self.plain_display_frame]


    #-------------------------------------------------------------------------
    # Edit Frames
    #-------------------------------------------------------------------------
    edit_frame_height = list_frame_height
    edit_frame_width = edit_frame_height / golden_ratio
    edit_frame_pos_x = ( screen_x - edit_frame_width ) / 2
    edit_frame_pos_y = list_frame_pos_y
        
    self.edit_frame = EditFrame(None, 'Edit', (edit_frame_pos_x, edit_frame_pos_y), (edit_frame_width, edit_frame_height))
    
    self.edit_frames = [self.edit_frame]
    
    
    #-------------------------------------------------------------------------
    # All Frames
    #-------------------------------------------------------------------------    
    self.frames = [self.background_frame] + self.search_frames + self.edit_frames
        
    self.set_colors()   
    
    
    self.background_frame.Show()
    self.edit_frame.Show()
    self.edit_frame.Show(0)   
    for frame in self.search_frames:
      frame.Show()
      
    self.list_frame.Show(0)
    self.pretty_display_frame.Show(0)
    self.plain_display_frame.Show(0)
      

    self.search_frame.set_focus()
    self.revision = -1
    self.last_note = None
    
    #-------------------------------------------------------------------------
    # Binding
    #-------------------------------------------------------------------------    
    
    self.Bind(wx.EVT_KEY_DOWN, self.OnChar)


    return True

  def reset_revision(self, note, force = False):
    if force:
      self.revision = -1
    else:
      if not self.last_note:
        self.revision = -1
      else:
        if not self.last_note['id'] == note['id']:
          self.revision = -1
    self.last_note = note
      
  def set_colors(self, schema = None):
    if not schema:
      schema = config.color_current
    
    color_dict = config.colors[schema]
    for frame in self.frames:
      frame.set_colors(color_dict)

  def OnCommand(self):
    keyword = self.search_frame.keywords_text.GetValue().strip()
    if self.note.run_command(keyword):
      keywords_text = self.search_frame.keywords_text
      keywords_text.SetValue(keyword + '!Done!')
      # hack for windows
      keywords_text.SetInsertionPointEnd()
      return True
    else:
      return False


        
  def OnChar(self, evt):
    code = evt.GetKeyCode()
    app = wx.GetApp()
    list_frame = app.list_frame
    display_frame = app.display_frame
    search_frame = app.search_frame
    edit_frame = app.edit_frame
    
    if not evt.AltDown():
      if list_frame.IsShown():
        note_vlistbox = list_frame.note_vlistbox
        if note_vlistbox:
          count = note_vlistbox.GetItemCount()
          current_selection = note_vlistbox.GetSelection()
          next_selection = current_selection
          if code == wx.WXK_UP:
            next_selection = ( current_selection - 1 ) % count
          elif code == wx.WXK_DOWN:
            next_selection = ( current_selection + 1) % count       
          if next_selection != current_selection:
            note_vlistbox.SetSelection(next_selection)
            list_frame.update_selection()
            search_frame.set_focus()
            return
    else:
      if list_frame.IsShown():
        if code == wx.WXK_LEFT:
          self.previous_revision()
          search_frame.set_focus()
          return
        elif code == wx.WXK_RIGHT:
          self.next_revision()
          search_frame.set_focus()
          return

    
    if code == wx.WXK_ESCAPE:
      if edit_frame.IsShown():
        self.toggle_mode()
        return
      else:
        self.OnClose()
        return
    
    if code == wx.WXK_RETURN:
      if self.current_mode == 'search':
        if self.OnCommand():
          return
        if not list_frame.IsShown():
          keywords = search_frame.get_keywords()
          if keywords:
            self.new_note(insert_keywords = True)
          else:
            search_frame.OnKeywords()
          return
        if display_frame.IsShown():
          self.edit_current()
          return
        else:
          if search_frame.get_keywords():
            self.new_note(insert_keywords = True)
            return
        
    if evt.CmdDown():
      if code in [ord('n'), ord('N')]:
        from_this = evt.AltDown()
        self.new_note(from_this)
        return
      if code in [ord('e'), ord('E')]:
        if self.current_mode == 'search':
          #self.export()
          return      
      if code in [ord('t'), ord('T')]:
        self.toggle_auto_sense()
        return
        
      
    if code == wx.WXK_BACK:
      if evt.CmdDown():
        if display_frame.IsShown():
          if evt.AltDown():
            self.hard_trash()
            return
          else:
            self.soft_trash()
            return
    if display_frame.IsShown():
      if display_frame is app.plain_display_frame:
        if code == wx.WXK_PAGEDOWN:
          display_frame.next_page()
          return
        elif code == wx.WXK_PAGEUP:
          display_frame.previous_page()
          return            
    
    evt.Skip()
    
  def previous_revision(self):
    current_note = self.display_frame.note
    if self.revision < 0:
      self.revision = current_note['revision']
    
    self.revision = ( self.revision - 2 ) % ( current_note['last_revision']  ) + 1
    self.search_frame.update(force = True, dry = True)
    
  def next_revision(self):
    current_note = self.display_frame.note
    if self.revision < 0:
      self.revision = current_note['revision']

    self.revision = self.revision % ( current_note['last_revision']  ) + 1
    self.search_frame.update(force = True, dry = True)
    
  def soft_trash(self):
    current_note = self.display_frame.note
    self.note.soft_trash(current_note)
    self.search_frame.update(force = True)

  def hard_trash(self):
    current_note = self.display_frame.note
    self.note.hard_trash(current_note)
    self.search_frame.update(force = True)
        
  def OnClose(self, evt=None):    
    self.search_frame.OnClose()
    
  def set_edit_mode(self):
    # hide all search frames
    self.search_frames_snapshot = []
    for frame in self.search_frames:
      self.search_frames_snapshot.append({'shown': frame.IsShown(), 'focus': frame.IsActive()})
    
    
    for frame in self.search_frames:
      frame.Show(0)
      
    
    self.background_frame.Raise()
    self.edit_frame.Show()
    self.edit_frame.set_focus()
    
    self.current_mode = 'edit'
    
  def set_search_mode(self):
    self.edit_frames_snapshot = []
    self.edit_frames_snapshot.append({'shown': self.edit_frame.IsShown(), 'focus': self.edit_frame.IsActive()})
    self.edit_frame.Show(0)
    self.background_frame.Raise()
    
    for i in range(len(self.search_frames)):
      if self.search_frames_snapshot[i]['shown']:
        self.search_frames[i].Show() 
    
    for i in range(len(self.search_frames)):
      if self.search_frames_snapshot[i]['focus']:
        self.search_frames[i].Raise()
        self.search_frames[i].SetFocus()
        # deal with search
        if i == 0:
          self.search_frames[i].set_focus()
    self.search_frame.update()
    self.current_mode = 'search'
    
  def toggle_mode(self):
    if self.current_mode == 'search':
      if self.edit_frame.note:
        self.set_edit_mode()
    else:
      if self.edit_frame.note:
        self.edit_frame.save_note()
      self.set_search_mode()

  def edit_current(self):
    current_note = self.display_frame.note
    self.edit_frame.load_note(current_note)
    self.toggle_mode()
    
  def new_note(self, from_this = False, insert_keywords = False):
    # new note
    note = self.note.dummy()
    if from_this:
      current_note = self.display_frame.note
      note['content'] = current_note['content']
    else:
      if insert_keywords:
        note['content'] = self.search_frame.get_keywords() + '\n\n'
        self.edit_frame.load_note(note, position_last = True)
      else:
        today = date.today()
        today_str = ('note.%2i.%2i.%s') % ( today.month, today.day, str(today.year)[2:])
        
        notes = self.note.search_header(today_str)
        
        if notes:
          self.edit_frame.load_note(notes[0])     
        else:
          note['content'] = today_str + '\n'*2
          self.edit_frame.load_note(note, position_last = True)
    self.toggle_mode()

  def export(self):
    note_list = self.list_frame.note_list
    self.note.export(note_list)


  def use_pretty_display(self, note):
    both_hidden = False
    if not self.plain_display_frame.IsShown() and not self.pretty_display_frame.IsShown():
      both_hidden = True
    if self.plain_display_frame.IsShown() and self.display_frame is self.plain_display_frame or both_hidden:
      self.display_frame = self.pretty_display_frame

      self.plain_display_frame.Show(0)
      self.display_frame.Show()
    
    self.display_frame.update_note(note)
    self.plain_display_frame.set_note(note)   
    
  def use_plain_display(self, note):
    both_hidden = False
    if not self.plain_display_frame.IsShown() and not self.pretty_display_frame.IsShown():
      both_hidden = True
    if self.pretty_display_frame.IsShown() and self.display_frame is self.pretty_display_frame or both_hidden:
      self.display_frame = self.plain_display_frame
      self.pretty_display_frame.Show(0)
      self.display_frame.Show() 
        
    self.display_frame.update_note(note)
    self.pretty_display_frame.set_note(note)
    
  def toggle_auto_sense(self):
    self.list_frame.auto_sense = not self.list_frame.auto_sense
    self.search_frame.update(force = True, dry = True)

def main():   
  app = Meno(redirect=False)
  # Import Psyco if available


  try:
#   import psyco
#   psyco.full()
#   psyco.log()
#   print 'psyco up :]'
    pass
  except ImportError:
    pass


  app.MainLoop()


main()

"""
profile.run('main()', 'profile.log')

import pstats

stats = pstats.Stats('profile.log')

stats.sort_stats('pcalls')

stats.print_stats()
"""